import { any } from "../core/logic";
import { isBlank } from "../core/utils";
import { Component, ComponentType } from "./Component";
import { Trans } from "./Trans";
import { Buffer } from "../gpu/types/Buffer";
import { Engine } from "../Engine";
/**
 * @memberof w.component
 */
class TransInstance extends Component {
    constructor(opts = {}) {
        opts.type = any(opts.type, ComponentType.TransInstance);
        super(opts);
        this.hash="transinstance";
        this._maxInstanceNum = any(opts.maxInstanceNum, 100);
        this._transArr = any(opts.trans, [new Trans(opts)]);
        this._transArr[0].instanceTrans=this;
        this.addConfigParam("instanceCount", 1);
        this.addParam("transinstance");
        this.autoUpdate = true;
        this.update();
    }
    set maxInstanceNum(v) {
        this._maxInstanceNum = v;
        this.addParam("transinstance");
        this.update();
    }
    get maxInstanceNum() {
        return this._maxInstanceNum;
    }
    get instanceCount() {
        return this._transArr.length;
    }
    getInstance(index){
      return this._transArr[index]
    }
    findInstance(key,value){
        let instance;
        for(let i=0;i<this._transArr.length;i++){
            if(this._transArr[i].parameter[key]==value){
                instance=this._transArr[i];
                instance.idx=i;
                break;
            }
        }
        return instance;
    }
    updateState() {
        this.setState(true);
    }
    updateHash () {
        let hash = '';
        this.getAll().forEach(([paramsId, param]) => {
            if(!(param && param.isConfig)) {
                hash = hash + paramsId;
            } else {
                
            }
        })
        this.hash = hash;
    }
    itemUpdate(){
        let transParam = this.getParam("transinstance");
        if(transParam){
            transParam.state=false;
            this.update();
        }
    }
    toGPU(meshCom) {
        let destroy=false;
        if (this._transArr.length > this.maxInstanceNum) {
            this.maxInstanceNum=this.maxInstanceNum*2;
            destroy=true;
            //throw new Error(`实例数:${this._transArr.length}超过maxInstanceNum:${this.maxInstanceNum},请提高maxInstanceNum`);
        }
        if(this.destroyParam){
            this.destroyParam.destroy();
        }
        if(destroy){
            let pa=this.getParam("transinstance");
            if(pa){
                this.destroyParam=pa
                pa.unBind(this);
                this.params.delete("transinstance");
            }
            this.grouplayouts1=null;
        }
        let transParam = this.getParam("transinstance");
        if (!transParam) {
            let data = new Float32Array(this.instanceCount * 32);
            for (let i = 0; i < this.instanceCount; i++) {
                data.set(this._transArr[i].matrixWorld.elements,i * 32);
                let normalMat = this._transArr[i].matrixWorld.clone().invert();
                normalMat.transpose();
                data.set(normalMat.elements,i * 32 + 16);
            }
            transParam = new Buffer({
                id: "transinstance",
                name: "transinstance",
                usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
                visibility: GPUShaderStage.VERTEX,
                type: "read-only-storage",
                size: 128 * this.maxInstanceNum,
                data
            });
            this.addParam("transinstance", transParam);
            transParam.state = true;
            data = null;//销毁
        } else {
            if (!transParam.state) {
                transParam.size = 128 * this.maxInstanceNum;//改变最大实例数。
                let data = new Float32Array(this.instanceCount * 32);
                for (let i = 0; i < this.instanceCount; i++) {
                    data.set(this._transArr[i].matrixWorld.elements,i * 32);
                    let normalMat = this._transArr[i].matrixWorld.clone().invert();
                    normalMat.transpose();
                    data.set(normalMat.elements,i * 32 + 16);
                }
                transParam.buffer(data);
                transParam.state = true;
                data = null;//销毁
            }
        }
        if (!this.grouplayouts1) {
          const params = this.getAllParams()
          let entriesGroup1 = [], entriesLayout1 = []
          this.defs = {}
          this.config={}
          for (let index = 0; index < params.length; index++) {
            const param = params[index];
            this.defs[param.name] = param.value;
            if(param.group===1){
              entriesGroup1.push(param.gpu.entry)
              entriesLayout1.push(param.gpu.layout)
            }else{
              this.config[param.name]=param.value
            }
          }
          if(meshCom.geometryEntriesGroup)entriesGroup1.push(...meshCom.geometryEntriesGroup)
          if(meshCom.geometrEntriesLayout)entriesLayout1.push(...meshCom.geometrEntriesLayout)
        
          this.grouplayouts1 = Engine.instance.device.createBindGroupLayout({
            label: "layout" + 1,
            entries: entriesLayout1
          });
          this.bindGroup1 = Engine.instance.device.createBindGroup({
            label: "bindGroup" + 1,
            layout: this.grouplayouts1,
            entries: entriesGroup1
          });
        }
        this.config["instanceCount"]=this.instanceCount;
    
    }
    add(trans) {
        trans.instanceTrans=this;
        this._transArr.push(trans);
        // trans.onChange(this.update);//trans变更触发transInstance变更。
        this.addConfigParam("instanceCount", this.instanceCount);
        this.addParam("transinstance");
        this.update();
        return this;
    }
    remove(id) {
        for (let i = this.instanceCount - 1; i >= 0; i--) {
            if (this._transArr[i].id == id) {
                this._transArr[i].instanceTrans=undefined;
                this._transArr.splice(i, 1);
                this.addConfigParam("instanceCount", this.instanceCount);
                this.addParam("transinstance");
                this.update();
                break;
            }
        }
        return this;
    }
    removeByIndex(index){
        if(this._transArr[index]){
            this._transArr[index].instanceTrans=undefined;
            this._transArr.splice(index, 1);
            this.addConfigParam("instanceCount", this.instanceCount);
            this.addParam("transinstance");
            this.update();
        }
    }
    transerUpdate(){
      for (let index = 0; index < this._transArr.length; index++) {
        const trans = this._transArr[index];
        trans.setState(false,"matrix");   
        trans.addParam("trans");
      }
  }
}
export { TransInstance }